﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Mimoza.UpdatePlugin
{
    class UpdateFileDownloader
    {
        const int c_DeafultConnPeriod = 30; // sec

        public UpdateFileDownloader()
        {
            AgentLayer.Communication.ReplyUpdatesFileChunk.RegisterInTransport();
        }

        public void Start(string updateFileName)
        {
            m_updateFileName = updateFileName;
            StartDownloadThread();
        }

        public void Stop()
        {
            if (m_workingThread != null)
            {
                m_bStopThread = true;
                m_actionEvent.Set();

                m_workingThread.Join();
                m_workingThread = null;
            }
        }

        public void SetServiceConnection(Transport.Connection connection)
        {
            m_serviceConnection = connection;
        }

        bool IsTestMode
        {
            get { return (m_serviceConnection != null); }
        }

        void StartDownloadThread()
        {
            Common.Logger.Log.Info("Mimoza.UpdatePlugin.UpdateFileDownloader.StartDownloadThread fileName - " +
                m_updateFileName.ToString() + "...");

            m_workingThread = new System.Threading.Thread(new
                System.Threading.ThreadStart(WorkingThread));

            m_actionEvent = new System.Threading.AutoResetEvent(false);

            m_workingThread.Start();
        }

        void WorkingThread()
        {
            Common.Logger.Log.Info("Mimoza.UpdatePlugin.UpdateFileDownloader.WorkingThread workingFileName - '" +
                m_updateFileName.ToString() + "'...");

            while (!m_bStopThread)
            {
                try
                {
                    using (Transport.Connection serverConnection = CreateServerConnection())
                    {
                        if (serverConnection != null)
                        {
                            if (DownloadFile(serverConnection))
                            {
                                UpdateSystem();
                                EraseUpdatesFile();
                                RestartHost();
                                return;
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    Common.Logger.Log.Warn("Mimoza.UpdatePlugin.UpdateFileDownloader.WorkingThread error - '" +
                        e.ToString() + "'.");
                    m_bStopThread = true;
                }

                int waitPeriod = c_DeafultConnPeriod;
                Mimoza.AgentLayer.Settings settings = Mimoza.AgentLayer.Settings.GlobalSettings;
                if (settings != null) waitPeriod = (int)(settings.CreateConnectionPeriod);

                m_actionEvent.WaitOne(TimeSpan.FromSeconds(waitPeriod).Milliseconds, false);
            }
        }

        bool DownloadFile(Transport.Connection connection)
        {
            using(FileStream fs = File.Open(m_updateFileName,FileMode.Open))
            {
                Guid updateId = GetUpdateIdFromFileName();
                int pos = (int)fs.Seek(0, SeekOrigin.End);

                Common.Logger.Log.Info("Mimoza.UpdatePlugin.UpdateFileDownloader.DownloadFile updateId - '" +
                        updateId.ToString() + "' pos - " + pos.ToString() + ".");

                bool bEof = false;
                do
                {
                    AgentLayer.Communication.RequestUpdatesFileChunk reqFileChunk = 
                        new AgentLayer.Communication.RequestUpdatesFileChunk( updateId, pos );

                    AgentLayer.Communication.ReplyUpdatesFileChunk replyFileChunk = connection.MakeRequest(reqFileChunk) 
                        as AgentLayer.Communication.ReplyUpdatesFileChunk;

                    if (replyFileChunk.ChunkSize>=0)
                    {
                        fs.Write(replyFileChunk.Body, 0, replyFileChunk.ChunkSize);
                        pos = replyFileChunk.Position + replyFileChunk.ChunkSize;
                    }

                    bEof = replyFileChunk.EndOfFile;
                }
                while (!bEof);
            }

            return true;
        }
        

        Transport.Connection CreateServerConnection()
        {
            if (IsTestMode) return m_serviceConnection;

            if (AgentLayer.Configuration.GlobalConfiguration != null)
            {
                Common.Logger.Log.Info("Mimoza.UpdatePlugin.UpdateFileDownloader.CreateServerConnection fileName - '" +
                        m_updateFileName + "'.");

                return AgentLayer.Configuration.GlobalConfiguration.HostConnection.CreateServerConnection();
            }
            return null;
        }

        void UpdateSystem()
        {
            if (IsTestMode) return;

            UpdateFileInstaller installer = new UpdateFileInstaller(m_updateFileName);

            installer.Install();
        }

        void EraseUpdatesFile()
        {
            if (IsTestMode) return;

            Common.Logger.Log.Info("Mimoza.UpdatePlugin.UpdateFileDownloader.EraseUpdatesFile fileName - '" +
                        m_updateFileName + "'.");

            File.Delete(m_updateFileName);
        }

        void RestartHost()
        {
            if (IsTestMode) return;

            Mimoza.AgentLayer.SystemPower.Reboot();
        }

        Guid GetUpdateIdFromFileName()
        {
            return new Guid(Path.GetFileNameWithoutExtension(m_updateFileName));
        }

        string m_updateFileName;

        System.Threading.Thread m_workingThread = null;
        System.Threading.AutoResetEvent m_actionEvent;
        volatile bool m_bStopThread = false;
        Transport.Connection m_serviceConnection;
    }
}
